package com.example.tpintegrador.messaging;

import android.widget.Toast;
import java.text.SimpleDateFormat;

import com.example.tpintegrador.data.ContactDataBaseHelper;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;

public class NetworkConnectivity {
	private static final String TAG = "NetworkConnectivityListener";

	private static final boolean DBG = false;
	
	private ContactDataBaseHelper database;

	private Context mContext;

	private State mState;

	private boolean mListening;

	private String mReason;

	private boolean mIsFailover;

	/** Network connectivity information */
	private NetworkInfo mNetworkInfo;

	/**
	 * In case of a Disconnect, the connectivity manager may have already
	 * established, or may be attempting to establish, connectivity with another
	 * network. If so, {@code mOtherNetworkInfo} will be non-null.
	 */
	private NetworkInfo mOtherNetworkInfo;

	private ConnectivityBroadcastReceiver mReceiver;

	private class ConnectivityBroadcastReceiver extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			SimpleDateFormat formato = new SimpleDateFormat(
					"dd/MM/yyyy HH:mm:ss");
			String fecha = formato.format(System.currentTimeMillis());
			if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)
					|| mListening == false) {
				Log.w(TAG, "onReceived() called with " + mState.toString()
						+ " and " + intent);

				return;
			}

			boolean noConnectivity = intent.getBooleanExtra(
					ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
			try {
				if (noConnectivity) {
					mState = State.NOT_CONNECTED;
					NotificacionConexion.notifyNetworkDisconnection(mContext);
					database.addConexion(fecha, "NN", "Desconectado");
				} else {
					mState = State.CONNECTED;
					mNetworkInfo = (NetworkInfo) intent
							.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
					
					switch(mNetworkInfo.getType())
					{
					case ConnectivityManager.TYPE_MOBILE:
						NotificacionConexion.notifyNetworkConnection(mContext,
								"3G");
						database.addConexion(fecha, "3G", "Conectado");
						break;
					case ConnectivityManager.TYPE_WIFI:
						NotificacionConexion.notifyNetworkConnection(
								mContext, "WI-FI");
						database.addConexion(fecha, "WI-FI", "Conectado");
						break;
					case ConnectivityManager.TYPE_WIMAX:
						NotificacionConexion.notifyNetworkConnection(
								mContext, "WI-MAX");
						database.addConexion(fecha, "WI-FI MAX","Conectado");
						break;
					}
					
				}
			} catch (Exception ex) {
				Toast toast = Toast.makeText(mContext, ex.toString(),
						Toast.LENGTH_LONG);
				toast.show();

			}

			mOtherNetworkInfo = (NetworkInfo) intent
					.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);

			mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
			mIsFailover = intent.getBooleanExtra(
					ConnectivityManager.EXTRA_IS_FAILOVER, false);

			if (DBG) {
				Log.d(TAG,
						"onReceive(): mNetworkInfo="
								+ mNetworkInfo
								+ " mOtherNetworkInfo = "
								+ (mOtherNetworkInfo == null ? "[none]"
										: mOtherNetworkInfo + " noConn="
												+ noConnectivity) + " mState="
								+ mState.toString());
			}

		}
	};

	public enum State {
		UNKNOWN,

		/** This state is returned if there is connectivity to any network **/
		CONNECTED,
		/**
		 * This state is returned if there is no connectivity to any network.
		 * This is set to true under two circumstances:
		 * <ul>
		 * <li>When connectivity is lost to one network, and there is no other
		 * available network to attempt to switch to.</li>
		 * <li>When connectivity is lost to one network, and the attempt to
		 * switch to another network fails.</li>
		 */
		NOT_CONNECTED
	}

	/**
	 * Create a new NetworkConnectivityListener.
	 */
	public NetworkConnectivity() {
		mState = State.UNKNOWN;
		mReceiver = new ConnectivityBroadcastReceiver();
	}

	/**
	 * This method starts for network connectivity state changes.
	 * 
	 * @param context
	 */
	public synchronized void start(Context context) {
		if (!mListening) {
			mContext = context;

			IntentFilter filter = new IntentFilter();
			filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
			context.registerReceiver(mReceiver, filter);
			// NotificacionConexion.notifyNetworkDisconnection(context);
			mListening = true;
		}
	}

	/**
	 * This method stops this class from listening for network changes.
	 */
	public synchronized void stop() {
		if (mListening) {
			mContext.unregisterReceiver(mReceiver);
			mContext = null;
			mNetworkInfo = null;
			mOtherNetworkInfo = null;
			mIsFailover = false;
			mReason = null;
			mListening = false;
		}
	}

	public State getState() {
		return mState;
	}

	public boolean isConnected() {
		return mState == State.CONNECTED;
	}

	/**
	 * Return the NetworkInfo associated with the most recent connectivity
	 * event.
	 * 
	 * @return {@code NetworkInfo} for the network that had the most recent
	 *         connectivity event.
	 */
	public NetworkInfo getNetworkInfo() {
		return mNetworkInfo;
	}

	/**
	 * If the most recent connectivity event was a DISCONNECT, return any
	 * information supplied in the broadcast about an alternate network that
	 * might be available. If this returns a non-null value, then another
	 * broadcast should follow shortly indicating whether connection to the
	 * other network succeeded.
	 * 
	 * @return NetworkInfo
	 */
	public NetworkInfo getOtherNetworkInfo() {
		return mOtherNetworkInfo;
	}

	/**
	 * Returns true if the most recent event was for an attempt to switch over
	 * to a new network following loss of connectivity on another network.
	 * 
	 * @return {@code true} if this was a failover attempt, {@code false}
	 *         otherwise.
	 */
	public boolean isFailover() {
		return mIsFailover;
	}

	/**
	 * An optional reason for the connectivity state change may have been
	 * supplied. This returns it.
	 * 
	 * @return the reason for the state change, if available, or {@code null}
	 *         otherwise.
	 */
	public String getReason() {
		return mReason;
	}

}
